package com.snack.common.utils;

import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;

public class HttpClient {
	private static final String BOUNDARY = "LamfireFormBoundaryucJiylDzwZWyoOSF";

	public static class ContentType {
		public static final String multipart_form_data = "multipart/form-data; boundary=" + BOUNDARY;
		public static final String application_x_www_form_urlencoded = "application/x-www-form-urlencoded";
	}

	private static final Logger LOGGER = Logger.getLogger(HttpClient.class.getName());
	private HttpURLConnection conn;
	private String charset = "UTF-8";
	private String contentType = ContentType.application_x_www_form_urlencoded;
	private String method = "GET";
	private final Map<String, String> requestHeaderMap = new HashMap<String, String>();
	private int connectTimeOut = 30000;
	private int readTimeOut = 30000;
	
	
	private DataOutputStream output = null;

	public void setCharset(String charset) {
		this.charset = charset;
	}

	public void setMethod(String method){
		this.method = method.toUpperCase();
	}
	
	public String getMethod(){
		return method;
	}

	public void setContentType(String contentType) {
		this.contentType = contentType;

	}
	
	public void post(byte[] postData) {
		if(output == null){
			throw new RuntimeException("method ["+this.method + "] output stream has not opened.");
		}
		try {
			output.write(postData);
			output.flush();
		} catch (IOException e) {
			LOGGER.error("send data exception.",e);
		}
	}

	public void setRequestHeader(String key, String value) {
		this.requestHeaderMap.put(key, value);
	}

	

	public void setConnectTimeout(int millis) {
		this.connectTimeOut = millis;
	}
	
	public void setReadTimeout(int millis){
		this.readTimeOut = millis;
	}

	public void open(String urlPath) throws IOException {
		URL url = new URL(urlPath);
		conn = (HttpURLConnection) url.openConnection();
		conn.setRequestMethod(method);
		conn.setRequestProperty("User-Agent","Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.120 Safari/535.2");
		conn.setReadTimeout(readTimeOut);
		conn.setConnectTimeout(connectTimeOut);
		conn.setUseCaches(false);
		conn.setDoInput(true);
		
		boolean isGetMethod = "GET".equalsIgnoreCase(method);
		if(isGetMethod){
			conn.setDoOutput(false);
			conn.setInstanceFollowRedirects(false);
		}else{
			conn.setDoOutput(true);
			conn.setInstanceFollowRedirects(true);
			conn.setRequestProperty("Connection", "Keep-Alive");
			conn.setRequestProperty("Charset", charset);
			conn.setRequestProperty("Content-Type", contentType);
		}
		
		for(Map.Entry<String, String> entry : requestHeaderMap.entrySet()){
			conn.setRequestProperty(entry.getKey(), entry.getValue());
		}
		
		// 打开连接
		conn.connect();

		if(!isGetMethod){
			//打开输出流
			output = new DataOutputStream( conn.getOutputStream() );
		}
	}

	public byte[] read() throws IOException {
		InputStream input = null;
		try {
			input = conn.getInputStream();
			ByteArrayOutputStream result = new ByteArrayOutputStream();
			IOUtils.copy(input, result);
			// 读取完成
			return result.toByteArray();
		} catch (IOException e) {
			throw e;
		} finally {
			if (input != null)
				input.close();
		}
	}

	public String readAsString() throws IOException {
		return readAsString("utf-8");
	}

	public String readAsString(String encoding) throws IOException {
		byte[] content = read();
		if(content == null)return null;
		return new String(content);
	}
	
	public String getResponseHeader(String key) {
		return conn.getHeaderField(key);
	}

	public Map<String, List<String>> getResponseHeaders() {
		return conn.getHeaderFields();
	}

	public String getContentEncoding() {
		return conn.getContentEncoding();
	}

	public int getContentLength() {
		return conn.getContentLength();
	}

	public int getResponseCode() throws IOException {
		return conn.getResponseCode();
	}

	public String getResponseMessage() throws IOException {
		return conn.getResponseMessage();
	}

	public void sendMultipartFormItem(String formItemName, String value) {
		StringBuffer buffer = new StringBuffer();
		buffer.append("\r\n--" + BOUNDARY + "\r\n");
		buffer.append("Content-Disposition: form-data; name=\"" + formItemName + "\"\r\n");
		buffer.append("Content-Type: text/plain;charset=" + charset + "\r\n\r\n");
		buffer.append(value);
		try {
			output.write(buffer.toString().getBytes());
			output.flush();
		} catch (IOException e) {
			LOGGER.error(e.getMessage(), e);
		}
	}

	public void sendMultipartFileAsByteArray(String formItemName, String fileName, byte[] bytes) {
		StringBuffer buffer = new StringBuffer();
		buffer.append("\r\n--" + BOUNDARY + "\r\n");
		buffer.append("Content-Disposition: form-data; name=\"" + formItemName + "\"; filename=\"" + fileName + "\"\r\n");
		buffer.append("Content-Type: application/octet-stream\r\n\r\n");
		try {
			output.write(buffer.toString().getBytes());
			output.write(bytes);
			output.flush();
		} catch (IOException e) {
			LOGGER.error(e.getMessage(), e);
		}
	}

	public void sendMultipartFile(String formItemName, File file) {
		FileInputStream fis = null;
		try {
			StringBuffer buffer = new StringBuffer();
			buffer.append("\r\n--" + BOUNDARY + "\r\n");
			buffer.append("Content-Disposition: form-data; name=\"" + formItemName + "\"; filename=\"" + file.getName() + "\"\r\n");
			buffer.append("Content-Type: application/octet-stream\r\n\r\n");
			output.write(buffer.toString().getBytes());
			fis = new FileInputStream(file);
			byte[] filebuffer = new byte[10240];
			while (true) {
				synchronized (filebuffer) {
					int amountRead = fis.read(filebuffer);
					if (amountRead == -1) {
						break;
					}
					output.write(filebuffer, 0, amountRead);
				}
			}
			output.flush();
		} catch (IOException e) {
			LOGGER.error(e.getMessage(), e);
		}
	}
	
	public void sendMultipartFinish(){
		String endstr = "\r\n--" + BOUNDARY + "--\r\n";
		byte[] endbytes = endstr.getBytes();
		try {
			output.write(endbytes);
		}catch (IOException e) {
			LOGGER.error(e.getMessage(), e);
		}
	}
	
	public void close(){
		try{
			if(output!=null){
				output.close();
			}
		}catch(Exception e){}
		conn.disconnect();
	}

}
